Repository navigation
Refactor DSHX to profile-owned Codex TUI surface - #17
Draft
code-new-bie wants to merge 60 commits into
Draft
code-new-bie wants to merge 60 commits into
code-new-bie wants to merge 60 commits into
Conversation
…pter Merge app-server-adapter -> product-adapter -> release-adapter inheritance into a single DshxPresentationAdapter. Method bodies stay verbatim per layer; base/product seams survive as explicit helpers so the former super.* call order remains auditable, and the merged dispatch table keeps release-layer routing first. The ownership guard now forbids shadow fork/seed state on the unified adapter while requiring subagent interruption to delegate through ctx.subagents.interrupt (reading DSH's durable parentSession header stays the sanctioned authority path). Ignore local .build/ and .upstream/ materialization workspaces.
src/protocol.mjs (deterministic protocol PoC), src/server.mjs (TCP WebSocket stub) and the TCP stub entry leave the production source tree for devtools/. bin/dshx-stub-local.mjs stays: it drives real-TUI smoke through the production local-IPC topology. Packaging already shipped only bin/dshx.mjs + src/cli + src/dsh + src/protocol(dir), so artifacts are unchanged; the production src tree no longer carries dead protocol code.
Add src/dsh/presentation-plugin.mjs exporting the official plugin shape (name / inject / Config / apply, named exports only): it starts the packaged bridge + adapter transport against the already-booted composition Context, publishes the endpoint as the dshxPresentation service, and returns transport disposal to the Cordis root Fiber. bootDshxPresentationRuntime() mounts that plugin through the Cordis dynamic-plugin API; bin/dshx now consumes the provided service instead of driving local-server imperatively, and root-fiber disposal stays the sole teardown authority (transport close no longer disposes the runtime when mounted as a plugin). The surface lock moves from hardcoded arrays in runtime-boot to the declarative cordis.patch.yml bundle patch, loaded through DSH's own optional-patch loader and failing closed when missing.
Topology and launcher lifecycle now describe the dshx-presentation Cordis plugin row, the declarative cordis.patch.yml surface lock, and the devtools/ location of the development-only protocol fixtures.
CI-grade disks boot the composition well inside the hardcoded 20s/10s; slow checkouts such as a WSL /mnt/c mount do not. DSHX_SMOKE_BOOT_TIMEOUT_MS and DSHX_SMOKE_DISPOSE_TIMEOUT_MS now raise the bounds without touching the script; defaults are unchanged.
…tui)
The package now declares dsh.bundle.patch -> ./cordis.patch.yml, whose
insert rows mount the surface through the official loader:
- dshx-startup resolves env/packaged defaults, provides dshxStartup
- dshx-presentation injects dshxStartup, hosts the local IPC transport,
publishes dshxPresentation, returns the disposer
The imperative mounting channel is gone: no ctx.plugin() call, no
launcher-owned patch file, and boot() drops its bareModuleBaseUrl anchor so
row names resolve from the profile directory exactly like the official CLI
(the healed profiles/node_modules fallback covers in-box packages).
bin/dshx becomes a thin bootstrap over official machinery: it ensures the
selected profile carries this exact package version via
'dsh plugin --profile <p> add <root>' (idempotent), boots the composition,
and spawns the TUI against the provided endpoint; root-fiber disposal owns
teardown. doctor gains a 'Surface profile' gate and counts the two row
services among its required services.
Runtime host services move to peerDependencies (dual-listed for dev);
only leaf parser libs stay dependencies, preserving the single-instance
rule that keeps profile installs from shadowing healed symlinks.
scripts/verify-bundle-install.mjs proves the full chain end to end with
real tooling: npm pack -> dsh plugin add into a temp DSH_HOME ->
--dump-config row assertions -> loader activation with live transport ->
no stateful-runtime shadowing.
- src/dsh/profile-bootstrap.mjs owns the official-machinery bootstrap (dsh CLI resolution: DSHX_DSH_BIN override -> dependency-local lib/bin.js -> PATH; satisfaction = exact version AND bundle-layer membership; DSHX_SKIP_PROFILE_BOOTSTRAP=1 escape hatch). bin/dshx and runtime-smoke both use it, so the smoke script works against the tui surface profile. - scripts/verify-bundle-install.mjs resolves dsh the same way and now runs in CI (linux-tui job) after the bridge build; core enables pnpm for the bootstrap-driven runtime-smoke step. - Ownership guard tracks the bootstrap module instead of the launcher. - README gains a Plugin usage section; RUNTIME-INTEGRATION lifecycle and doctor description reflect loader-mounted rows and the profile gate.
The peerDependency pin is declarative only — profile installs never resolve peers, so a host running a different DSH release would fail with mysterious API errors. dshxRuntimeProfile now reads the version of the installation that will actually boot and fails loud with an actionable message (supported line <-> found version) when they diverge. The supported line's single source of truth is the manifest's @deepseek-ai/dsh peerDependency.
The plugin spec carries no host-version gates and official bundles declare peer ranges only. Keep the tested line as honest metadata (manifest peer pin + warn-once at boot naming both versions), but proceed on any installed release.
Product scope: replicate only Codex's TUI shell — everything else is DSH.
Make the codebase say so structurally:
src/tui-protocol/
shapes.mjs wire-format dictionary (former codex-shapes)
adapter.mjs app-server method routing + projection orchestration
Domain modules under src/dsh keep DSH vocabulary; the ownership guard now
asserts the dictionary lives only in tui-protocol and that no codex-named
module returns to src/dsh. Residual lowercase field mappings inside domain
modules are gradual-cleanup items, tracked by the same guard's placement
checks.
- Staged release package keeps host services as peerDependencies and ships only leaf parser libraries as dependencies: profile installs stay free of stateful runtime copies (single-instance rule) and never trip pnpm's build-script gate (node-pty/koffi/protobufjs all live in the healed host closure instead). - Shrinkwrap root records the staged peerDependencies. - Accept both npm pack --json shapes (array pre-10, name-keyed object since scoped records) — the old packed[0] access broke every scoped release.
verify-bundle-install gains a release flavor: when dist/release carries a packaged artifact, it installs that exact tarball into a fresh profile via the official command and proves loader activation with zero environment overrides — endpoint live, bridge resolved from the installed copy's own dist/bin, no stateful runtime shadowing. DSHX_REQUIRE_RELEASE=1 turns the missing-artifact skip into a failure for CI wiring. Probe runs as a real file because the hmr row resolves process.argv[1]. Legacy test filenames follow the modules into the tui-protocol naming.
… dialect user-input, plan-presentation, session-fork, thread-title, history-pages and skills are DSH->Codex view builders consumed only by the protocol layer; they move under src/tui-protocol/ so src/dsh converges on true domain concerns. token-usage and tool-presentation stay shared with the domain-side thread-controller for now.
…metadata Bare `dsh --profile tui` mounts the surface and waits passively; mirror the official web surface's printUrl precedent so the state is always visible instead of a silent hang. Root manifest gains its repository field.
…bundle After each platform tarball is built, run verify-bundle-install with DSHX_REQUIRE_RELEASE=1: official install into a fresh profile, composed tree assertions, loader activation with zero environment overrides, and the single-instance rule — on Linux and Windows both.
Set CARGO_PROFILE_RELEASE_DEBUG=0 (user-overridable) and strip the copied Unix binaries. The Linux TUI drops from 1.1GB to 222MB and the platform tarball from 272MB to 85MB with identical behavior; Windows keeps its debug symbols beside the exe as before.
The production launcher no longer imports or boots any harness build from
our package: bin/dshx bootstraps the surface profile via the official
plugin command, then spawns the user's own 'dsh --profile tui'. The
loader mounts our rows inside THAT installation, so credentials parsing,
service registries and every other harness behavior come from a single
build — the user's — eliminating the dual-build divergence this machine
demonstrated (system vs registry copies of the same version string).
Interactive attachment moved into the presentation row (opt-in via
DSHX_ATTACH set only by our launcher): raw-mode TUI turns Ctrl+C into a
key event, so the host's SIGINT handler never fires during interaction;
non-TTY contexts degrade gracefully to a passive endpoint with a visible
listening hint. local-server drops its runtime-boot import edge, keeping
row-module graphs free of package-side harness builds.
Adoptive compatibility stance: peerDependencies become an advisory floor
('>=0.1.0-rc.8', no upper bound); the exact tested line stays as an
explicit constant surfaced through a one-shot startup warning on any
other installed release.
…stic
Production launcher zero-imports harness builds: bootstrap the surface
profile via the official plugin command, then spawn the user's own
'dsh --profile tui'. Their installation composes everything, parses their
state files, and hosts our loader-mounted rows; the pinned TUI attaches
from inside the presentation row (opt-in DSHX_ATTACH from our launcher,
raw-mode Ctrl+C stays a key event; non-TTY degrades to a passive endpoint
with a visible listening hint).
dsh CLI resolution now prefers the user's PATH installation over the
dependency-local copy, and runtime-boot anchors composition/healing at
that same installation — eliminating the dual-build divergence this
machine demonstrated (system vs registry copies sharing one version
string, with incompatible credentials parsing).
Adoptive compatibility: peerDependencies become an advisory floor
('>=0.1.0-rc.8', unbounded); the exact tested line is an explicit
constant surfaced as a one-shot warning on other installed releases.
local-server drops its runtime-boot import edge so row graphs stay free
of package-side harness builds. doctor's harness gate now probes the
user's real installation instead of an in-process boot.
A TUI protocol timeout is undiagnosable when the two events that explain it — bridge exit and response-send failure — are gated behind DSHX_DEBUG. They now print unconditionally with a [dshx] prefix; debug-gated verbose logging stays as-is.
Introduce a direct NDJSON stdio transport inside the already-mounted DSH composition, selected through the launcher's official cmdlineArgs service. Keep the legacy bridge as a migration fallback until the pinned Codex TUI is switched over. Also fix presentation-row lifecycle ownership: plugin apply now completes after initialization and requests bounded host exit through appExit when the attached TUI or stdio client leaves, avoiding loader.await/readiness deadlock.
Switch the pinned Codex TUI to spawn the user's official dsh profile as a local NDJSON stdio app-server. Classify that child as a local backend so Codex remote-workspace semantics never leak into DSHX. Remove the Unix-socket/WebSocket bridge, Node socket host and self-boot runtime helpers. Rework smoke and bundle verification to exercise only official dsh plugin/profile machinery, including initialize and bounded EOF/appExit shutdown.
Separate the compatible DSH peer range from the exact CI baseline, update ownership assertions for the official-host-only architecture, and move platform PTY gates to the stdio backend.
Package only the pinned TUI and standard DSH bundle, record the local stdio transport in provenance, and align release verification with the official-host-only runtime boundary.
Treat the underlying stdin end event as the authoritative stdio EOF signal, drain pending protocol work, then request the official DSH appExit. Keep readline close as a fallback and make the integration smoke expose the EOF/appExit stages with a bounded shutdown deadline.
Merged
Owner
Author
|
Final external-release handoff for exact candidate
The next external action is therefore exactly: git fetch origin release/1.0-rc
git tag v1.0.0-rc.9 3729f2a6e5dc6422a21875e86c64ebac3fb95297
git push origin v1.0.0-rc.9That tag must trigger the repository's existing Keep this PR draft and do not merge/promote stable |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refactors DSHX into a standard DeepSeek Harness TUI surface bundle whose only product runtime is the user's official DSH profile/composition.
Final architecture:
dshxis a thin UX alias that ensures the bundle is installed, then launches officialdsh --profile tuidshx-startupanddshx-presentationinside that existing compositionExact candidate:
3729f2a6e5dc6422a21875e86c64ebac3fb95297.The final delta from the previously green
a7430794...candidate is.gitattributesforcingpackage-lock.jsontoeol=lf, preserving reviewed lockfile byte identity across Windows/macOS/Linux so release provenance can require one exactsourceLockSha256.Exact-SHA automated evidence is now green:
33184987198: Core / Node 24 and Linux pinned Codex TUI both success; frozen graph, DSH closure, unit/contract suite, ownership boundary, official profile lifecycle, native build, thin-fork invariants, official bundle activation and Linux PTY/CJK/resize all passed33184987192: Windows pinned build + ConPTY/CJK and macOS pinned build + PTY/CJK/resize both success; platform summary success33185259423: platform package, release-bundle activation, clean install without a second DSH runtime and provenance checks success33185304658: Linux x64, Windows x64, macOS arm64 and macOS x64 each built, exercised the native terminal smoke, packaged, activated through official DSH and clean-installed; cross-platform provenance/checksum aggregation successrelease/1.0-rcnow points to this exact candidate SHANo automated architecture/runtime/package blocker is currently known.
Remaining release blockers are intentionally external to source correctness:
v1.0.0-rc.9) at the currentrelease/1.0-rchead so the repository's tag-triggeredReleaseworkflow produces immutable RC artifacts under real release semantics; the currently connected GitHub tool does not expose Git-tag creationThis PR remains draft and must not be merged or promoted to stable
v1.0.0until #12–#15 satisfy their formal RC/tag closure rules. Do not solve any remaining release failure by introducing a shadow DSH runtime or weakening the ownership/security boundary.